<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>PocketBuddy</title>
    <script src="build/litegraph.js"></script>
    <link rel="stylesheet" href="css/litegraph.css">
    <style>
        body {
            margin: 0;
            padding: 0;
            background-color: #333;
            color: white;
            font-family: "Noto Sans SC";
            overflow: hidden;
        }
        #mycanvas {
            width: 100vw;
            height: 100vh;
            background-color: #1a1a1a;
        }
        .title {
            position: absolute;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            z-index: 1000;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
        }
        canvas {
            image-rendering: pixelated;
            image-rendering: crisp-edges;
        }
    </style>
</head>
<body>
    <h1 class="title">PocketBuddy 系统状态</h1>
    <canvas id="mycanvas"></canvas>

    <script>
        var graph = new LGraph();
        var canvas = new LGraphCanvas("#mycanvas", graph);
        
        function setHighDPI() {
            const pixelRatio = window.devicePixelRatio || 1;
            const canvas = document.getElementById('mycanvas');
            const width = canvas.offsetWidth * pixelRatio;
            const height = canvas.offsetHeight * pixelRatio;
            
            canvas.width = width;
            canvas.height = height;
            canvas.getContext('2d').scale(pixelRatio, pixelRatio);
        }
        
        const colors = {
            io: '#3498db',
            core: '#2ecc71',
            cloud: '#9b59b6',
            highlight: '#ffeb3b'  // 高亮颜色
        };

        // 基础节点类
        class BaseNode {
            constructor() {
                this.size = [240, 80];
                this.properties = { 
                    description: "",
                    isHighlighted: false
                };
                this.shape = LiteGraph.BOX_SHAPE;
                this.title_color = "#000";
            }
            
            onDrawForeground(ctx) {
                // 绘制描述文字
                if (this.properties.description) {
                    ctx.save();
                    ctx.font = "12px";
                    ctx.fillStyle = "#fff";
                    ctx.fillText(this.properties.description, 10, this.size[1] - 10);
                    ctx.restore();
                }

                // 如果节点被高亮，绘制边框效果
                if (this.properties.isHighlighted) {
                    ctx.save();
                    ctx.strokeStyle = colors.highlight;
                    ctx.lineWidth = 3;
                    ctx.beginPath();
                    ctx.roundRect(2, 2, this.size[0] - 4, this.size[1] - 4, 8);
                    ctx.stroke();
                    ctx.restore();
                }
            }

            // 高亮方法
            highlight() {
                // 取消其他节点的高亮
                graph.findNodesByClass(BaseNode).forEach(node => {
                    node.properties.isHighlighted = false;
                });
                this.properties.isHighlighted = true;
                graph.setDirtyCanvas(true);
            }

            // 取消高亮
            unhighlight() {
                this.properties.isHighlighted = false;
                graph.setDirtyCanvas(true);
            }
        }

        // IO 节点
        class TTSNode extends BaseNode {
            constructor() {
                super();
                this.title = "语音合成";
                this.color = colors.io;
                this.addInput("prompt", "text");
            }
        }

        class ASRNode extends BaseNode {
            constructor() {
                super();
                this.title = "语音识别";
                this.color = colors.io;
                this.addOutput("prompt", "text");
            }
        }

        class LCDNode extends BaseNode {
            constructor() {
                super();
                this.title = "LCD显示屏";
                this.color = colors.io;
                this.addInput("display", "image");
            }
        }

        class OLEDNode extends BaseNode {
            constructor() {
                super();
                this.title = "OLED显示屏";
                this.color = colors.io;
                this.addInput("status", "image");
            }
        }

        class CameraNode extends BaseNode {
            constructor() {
                super();
                this.title = "摄像头";
                this.color = colors.io;
                this.addOutput("camera", "video");
            }
        }

        // 核心节点
        class PocketBuddyNode extends BaseNode {
            constructor() {
                super();
                this.title = "PocketBuddy端侧模型";
                this.color = colors.core;
                this.addInput("prompt", "text");
                this.addInput("vision", "video");
                this.addOutput("response", "text");
                this.addOutput("display", "image");
                this.addOutput("status", "image");
                this.addOutput("llm@cloud", "text");
                this.addOutput("vlm@cloud", "video");
                this.size = [320, 160];
                this.properties.description = "嵌入式智能处理单元";
            }
        }

        // 云端节点
        class CloudLLMNode extends BaseNode {
            constructor() {
                super();
                this.title = "Qwen Max@CLOUD";
                this.color = colors.cloud;
                this.addInput("prompt", "text");
                this.size = [280, 100];
                this.properties.description = "云端大模型";
            }
        }

        class CloudVisionNode extends BaseNode {
            constructor() {
                super();
                this.title = "Qwen Max VL@CLOUD";
                this.color = colors.cloud;
                this.addInput("vision", "video");
                this.size = [280, 100];
                this.properties.description = "云端视觉模型";
            }
        }

        // 注册节点类型
        LiteGraph.registerNodeType("IO/TTS", TTSNode);
        LiteGraph.registerNodeType("IO/ASR", ASRNode);
        LiteGraph.registerNodeType("IO/LCD", LCDNode);
        LiteGraph.registerNodeType("IO/OLED", OLEDNode);
        LiteGraph.registerNodeType("IO/CAMERA", CameraNode);
        LiteGraph.registerNodeType("Core/PocketBuddy", PocketBuddyNode);
        LiteGraph.registerNodeType("Cloud/LLM", CloudLLMNode);
        LiteGraph.registerNodeType("Cloud/VisionModel", CloudVisionNode);

        // 添加节点
        function addNode(type, pos) {
            var node = LiteGraph.createNode(type);
            node.pos = pos;
            graph.add(node);
            return node;
        }

        // 创建节点（优化布局）
        const tts = addNode("IO/TTS", [100, 100]);
        const asr = addNode("IO/ASR", [100, 220]);
        const lcd = addNode("IO/LCD", [100, 340]);
        const oled = addNode("IO/OLED", [100, 460]);
        const camera = addNode("IO/CAMERA", [100, 580]);
        
        const pocketBuddy = addNode("Core/PocketBuddy", [500, 340]);
        
        const cloudLLM = addNode("Cloud/LLM", [900, 260]);
        const cloudVision = addNode("Cloud/VisionModel", [900, 420]);

        // 连接节点
        function connectNodes() {
            pocketBuddy.connect(0, tts, 0)
            pocketBuddy.connect(1, lcd, 0)
            pocketBuddy.connect(2, oled, 0)
            pocketBuddy.connect(3, cloudLLM, 0)
            pocketBuddy.connect(4, cloudVision, 0)

            asr.connect(0, pocketBuddy, 0)
            camera.connect(0, pocketBuddy, 1)
        }

        connectNodes();

        // 设置图形
        graph.start();
        setHighDPI();
        canvas.setZoom(0.8);
        canvas.centerOnNode(pocketBuddy);

        // 响应式处理
        window.addEventListener('resize', function() {
            setHighDPI();
            canvas.resize();
        });

        // 暴露全局方法用于编程控制高亮
        window.highlightNode = function(nodeTitle) {
            const node = graph.findNodesByType(nodeTitle)[0];
            if (node) {
                node.highlight();
            }
            graph.setDirtyCanvas(true);

        };

        window.unhighlightAll = function() {
            graph._nodes.forEach(node => {
                node.unhighlight();
            });
            graph.setDirtyCanvas(true);
        };

        setInterval(() => {
            fetch("/api/getStatus", {
                method: "POST"
            }).then(res => res.json()).then(data => {
                window.unhighlightAll();
                if (data.currentNodeName) {
                    window.highlightNode(data.currentNodeName);
                }
            });
        }, 1000);
    </script>
</body>
</html>